import java.io.*;
import java.util.*;
import java.text.*;
/**
 * Takes a comment as a SpecialNode, converts the comment
 * text into LaTeX, extracts section, keyword and math information.
 * @author James Stanier
 */
public class CommentTranslator {
	
	private int stringIndex;
	private char current;
	private String content;
	private String sectionTitle;
	private String output;
	private ArrayList<KeywordToken> keywords;
	private boolean open;
	private boolean endLoop;
	private int whitespaceCount;
	
	/**
	 * Constructor.
	 * @param n The comment being translated as a SpecialNode.
	 */
	public CommentTranslator(SpecialNode n) {
		whitespaceCount = 0;
		endLoop = false;
		content = n.getContents().trim();
		stringIndex = 0;
		output = "";
		keywords = new ArrayList<KeywordToken>();
		try {
			current = content.charAt(stringIndex);
		}
		catch (Exception e) {
			System.err.println("Init error. " + e); 
		}
	}
	
	/**
	 * The translation method.
	 */
	public void translate() throws Exception {
		String buffer = "";
			
			for(int i = 0; i < 3; i++) {
				getNextChar();
			}
			while(Character.isWhitespace(current)) {
				getNextChar();
			}
			
			buffer += current;
			
			// Check for !open or !shut
			for(int i = 0; i < 4; i++) {
				getNextChar();
				buffer += current;
			}
			
			
			if(buffer.equals("!open") || buffer.equals("!shut")) {

				if(buffer.equals("!open")) {
					open = true;
				}
				else {
					open = false;
				}
				buffer = "";
				getNextChar();
				
				// Advance to first proper character
				while(Character.isWhitespace(current)) {
					getNextChar();
				}
				
				// * Optional section header *
				if(current == '*' && open == true) {
					// Advance to start of title
					getNextChar();
					while(current != '*') {
						
						if(current == '}' || current == '{') {
							buffer += "\\" + current;
							getNextChar();
						}
						else if(current == '\\') {
							buffer += "$\\backslash$";
							getNextChar();
						}
						else {
							buffer += current;
							getNextChar();
						}
						if(stringIndex == content.length()-1) {
							throw new Exception("1");
							
						}
					}
					sectionTitle = buffer;
					buffer = "";
					
					// Advance past closing *
					getNextChar();
					
					// Trim leading whitespace
					while(Character.isWhitespace(current)) {
						getNextChar();
					}
				}
				else {
					sectionTitle = null;
				}
				
				
				while(stringIndex < content.length() && endLoop == false) {
					
					// * Math mode markup *
					if(current == '$') {
						getNextChar();
						while(current != '$') {
							
							if(current == '}' || current == '{') {
								buffer += "\\" + current;
								getNextChar();
							}
							else {
								buffer += current;
								getNextChar();
							}
							if(stringIndex == content.length()-1) {
								throw new Exception("2");
								
							}
						}
						output += "$" + buffer + "$";
						buffer = "";
						getNextChar();
						if(current == '.' || current == ',' || current == ':' || current == ';' || current == ')') {
							// Fine, no extra space needed.
						}
						else {
							output+= " ";
						}
					}
					
					// * Keyword markup *
					else if(current == '|') {
						getNextChar();
						while(current != '|') {
							
							if(current == '}' || current == '{') {
								buffer += "\\" + current;
								getNextChar();
							}
							else if(current == '\\') {
								buffer += "$\\backslash$";
								getNextChar();
							}
							else {
								buffer += current;
								getNextChar();
							}
							if(stringIndex == content.length()-1) {
								throw new Exception("3");
								
							}
						}
						// Add to keywords array for reference
						keywords.add(new KeywordToken(buffer));
						
						// Text is italic in output
						output += "\\textit{" + buffer + "}";
						buffer = "";
						// Advance past trailing |
						getNextChar();
						if(current == '.' || current == ',' || current == ':' || current == ';' || current == ')') {
							// Fine, no extra space needed.
						}
						else {
							output+= " ";
						}
					}
					
					// * Escape character *
					else if(current == '/') {
						getNextChar();
						
						buffer += current;
						output += buffer;;
						buffer = "";
						getNextChar();
					}
					
					
					// If none of the above, text is regular
					else {
						while(current != '$' || current != '*' || current != '|') {
							
							if(Character.isWhitespace(current)) {
								if(whitespaceCount == 0) {
									buffer += " ";
									getNextChar();
									whitespaceCount++;
								}
								else {
									getNextChar();
									whitespaceCount++;
								}	
							}
							else {
								
								if(current == '{' || current == '}') {
									buffer += "\\" + current;
									getNextChar();
									whitespaceCount = 0;
								}
								else if(current == '\\') {
									buffer += "$\\backslash$";
									getNextChar();
									whitespaceCount = 0;
								}
								else {
									buffer += current;
									getNextChar();
									whitespaceCount = 0;
								}
							}
							if(stringIndex != content.length()) {
								break;
							}
						}
						output += buffer;
						buffer = "";
					}
				}
			}
			else {
				throw new Exception("4");
			}
		
		// Trim trailing comment
		
		if(output.endsWith(";*/")) {
			String s = "";
			for(int i = 0; i < output.length()-3; i++) {
				s += output.charAt(i);
			}
			output = s;
		}
		
	}
	
	/**
	 * Used for throwing exceptions upon errors.
	 * @param s The exception description.
	 * @throws Exception
	 */
	public void error(String s) throws Exception {
		throw new Exception(s);
	}
	
	/**
	 * Get the next character in the comment.
	 */
	public void getNextChar() {
		if(stringIndex + 1 != content.length()) {
			current = content.charAt(++stringIndex);
		}
		else {
			endLoop = true;
		}
	}
	
	/**
	 * Get the title of the translated comment.
	 * @return The title as a String.
	 */
	public String getTitle() {
		return sectionTitle;
	}
	
	/**
	 * Get whether the comment starts with !open
	 * @return Whether the comment starts with !open as a boolean.
	 */
	public boolean isOpen() {
		return open;
	}
	
	/**
	 * Get all declared keywords in the comment.
	 * @return Declared keywords.
	 */
	public ArrayList<KeywordToken> getKeywords() {
		return keywords;
	}
	
	/**
	 * Get the translated output of the comment.
	 * @return The comment formatted in LaTeX.
	 */
	public String getOutput() {
		return output;
	}
	
	/**
	 * Print the title to the console.
	 */
	public void printTitle() {
		System.out.println("Section title is: " + sectionTitle);
	}
	
	/**
	 * Get the list of all keywords.
	 * @return All keywords declared.
	 */
	public String printKeywords() {
		String o = "";
		for(int i = 0; i < keywords.size(); i++) {
			o += keywords.get(i) + "\n";
		}
		return o;
	}
}
